#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
#include "component/aggregator.h"
#include "utils/to_ostream.h"
using namespace tdl;

// uid, ip, ua, item_num
typedef make_type_list<uint32_t, uint32_t, string, uint32_t>::type row_type;

enum { AGT_KEY = 0 };
enum { AGT_FIELD_UID = 0, AGT_FIELD_IP = 1, AGT_FIELD_UA = 2, AGT_FIELD_ITEM_NUM = 3 };
enum { AGT_FUNC_COUNT = 0, AGT_FUNC_COUNT_DISTINCT_IP = 1, AGT_FUNC_SUM_ITEM_NUM = 2 };

TDL_DECLARE_AGT_FUNC(row_type, agt_func);


int main(int argc, char* argv[])
{
	// select uid, count(*), count(distinct ip), sum(item_num) group by uid
	aggregator<row_type, 
			   int2type<AGT_KEY>, 
			   agt_func::count<AGT_FIELD_UID>, 
			   agt_func::count_distinct<AGT_FIELD_IP>, 
			   agt_func::sum<AGT_FIELD_ITEM_NUM> 
			  > agtor;

	for(uint32_t i = 3; i < 20; i++)
	{
		cout << i % 4 << "   " << i / 5 << "   " << i << endl;
		agtor.collect(i % 4, i / 5, "MSIE", i);
	}

	cout << endl << agtor.select_agt() << endl;

	// select uid from (select uid, count(*) as cnt, count(distinct ip), sum(item_num) group by uid) as t where cnt=4
	cout << agtor.select_agt_cond<agt_cond::equal<AGT_FUNC_COUNT, 4> >() << endl;

	// select uid from (select uid, count(*), count(distinct ip) as ip_cnt, sum(item_num) as item_cnt group by uid) as t 
	// where ip_cnt>3 and item_cnt<45
	typedef cond_and<agt_cond::greater<AGT_FUNC_COUNT_DISTINCT_IP, 3>, agt_cond::less<AGT_FUNC_SUM_ITEM_NUM, 45> > cond_type1;
	cout << agtor.select_agt_cond<cond_type1>() << endl;

	// select uid from (select uid, count(*) as cnt, count(distinct ip) as ip_cnt, sum(item_num) as item_cnt group by uid) as t 
	// where ((cnt=4 and ip_cnt>3) or (cnt=5 and item_cnt<60)) and (ip_cnt*100/cnt)>40
	typedef cond_and<
					 cond_or<
							cond_and<agt_cond::equal<AGT_FUNC_COUNT, 4>, agt_cond::greater<AGT_FUNC_COUNT_DISTINCT_IP, 3> >, 
							cond_and<agt_cond::equal<AGT_FUNC_COUNT, 5>, agt_cond::less<AGT_FUNC_SUM_ITEM_NUM, 60> > 
						   >, 
					 agt_cond::ratio_greater<AGT_FUNC_COUNT_DISTINCT_IP, AGT_FUNC_COUNT, 40>
				   > cond_type2;
	cout << agtor.select_agt_cond<cond_type2>() << endl;
	
	cout << (agtor.exist_key<cond_type2>(1) ? "1 exist" : "1 not exist") << endl;

	cout << agtor.select_key_cond<cond_type2>() << endl;

	agtor.clear();

	return 0;
}

